﻿/* 
* Copyright (c) 2009, The University of Texas at Austin
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, 
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, 
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, 
* this list of conditions and the following disclaimer in the documentation and/or other materials 
* provided with the distribution.
*
* Neither the name of The University of Texas at Austin nor the names of its contributors may be 
* used to endorse or promote products derived from this software without specific prior written 
* permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using Bio.Data.Providers;
using Bio.Data.Providers.Interfaces;
using BioBrowser.Models;
using BioBrowser.Views;
using JulMar.Windows;
using JulMar.Windows.Mvvm;
using JulMar.Windows.Interfaces;

namespace BioBrowser.ViewModels
{
    public class WorkspaceViewModel : SelectionViewModel
    {
        private readonly Workspace _workspace;
        internal Workspace WorkspaceData { get { return _workspace;} }

        public bool IsOpen { get; private set; }
        public MTObservableCollection<BioCategoryViewModel> Categories { get; private set; }

        public WorkspaceViewModel(Workspace workspace)
        {
            _workspace = workspace;
            Header = _workspace.Name;
            Image = @"images/tagged_heart.png";
            Categories = new MTObservableCollection<BioCategoryViewModel>();

            // Populate sequence loaders
            var loaders = Extensions.Current.DataProviders.Where(bdl => (bdl.SupportedTypes & (BioFormatType.Sequence | BioFormatType.AlignedSequence)) > 0).Select(bdl => bdl);
            if (loaders.Count() > 0)
                Categories.Add(new BioCategoryViewModel() { Header = "Sequence Alignments", Image = "images/alignment.ico", FormatLoaders = loaders, IsExpanded = true });

            // Populate structure loaders
            loaders = Extensions.Current.DataProviders.Where(bdl => (bdl.SupportedTypes & (BioFormatType.Structure | BioFormatType.Structure2D)) > 0).Select(bdl => bdl);
            if (loaders.Count() > 0)
                Categories.Add(new BioCategoryViewModel { Header = "Structure Diagrams", Image = "images/secondaryStruct.ico", FormatLoaders = loaders, IsExpanded = true });

            // 3D molecular viewers
            loaders = Extensions.Current.DataProviders.Where(bdl => (bdl.SupportedTypes & (BioFormatType.MoleculeStructure)) > 0).Select(bdl => bdl);
            if (loaders.Count() > 0)
                Categories.Add(new BioCategoryViewModel { Header = "Molecular Structure (3D)", Image = "images/molecule.ico", FormatLoaders = loaders, IsExpanded = true });

            if (Categories.Count > 0)
                IsExpanded = true;

            // Decide where each file goes -- we must have the proper loader available or we do not display the file.
            foreach (var file in _workspace.DataSources)
                AddFileToWorkspace(file);
        }

        private void AddFileToWorkspace(WorkspaceEntry entry)
        {
            var owner = (from svm in Categories
                         from bl in svm.FormatLoaders
                         where bl.Key == entry.LoaderKey
                         select new {ViewModel = svm, FormatLoader = bl}).FirstOrDefault();
            if (owner != null && owner.ViewModel != null && owner.FormatLoader != null)
            {
                IBioDataLoader loader = owner.FormatLoader.Create(entry.LoaderData);
                if (loader != null)
                {
                    var dvm = new OpenBioDataViewModel(entry.LoaderData, entry.FormatType, loader, owner.FormatLoader);
                    dvm.CloseRequest += OnDataFileClosing;
                    owner.ViewModel.Children.Add(dvm);
                }
            }
            else
            {
                var uiMessage = Resolve<IMessageVisualizer>();
                if (uiMessage != null)
                {
                    uiMessage.Show("Error loading workspace",
                                   "Could not resolve loader provider for " + entry.FormatType +
                                   ".  File will be ignored.", MessageButtons.OK);
                }
            }
        }

        private void OnDataFileClosing(object sender, EventArgs e)
        {
            OpenBioDataViewModel dvm = (OpenBioDataViewModel) sender;
            dvm.CloseRequest -= OnDataFileClosing;

            var parentContainer = Categories.Where(svm => svm.Children.Contains(dvm)).FirstOrDefault();
            if (parentContainer != null)
                parentContainer.Children.Remove(dvm);
        }

        /// <summary>
        /// This populates the context menu for the category
        /// </summary>
        public override List<MenuItem> MenuOptions
        {
            get
            {
                IsSelected = true;
                return new List<MenuItem>
                   {
                       new MenuItem("O_pen All Data Sources") { Command = new DelegatingCommand(OnOpenWorkspace, OnCanOpenWorkspace) },
                       new MenuItem("C_lose All Views") { Command = new DelegatingCommand(OnCloseWorkspace, OnCanCloseWorkspace) },
                       new MenuItem("Close _Workspace") { Command = new DelegatingCommand(OnRemoveWorkspace) },
                       new MenuItem(),
                       new MenuItem("Add Open _Data File") { Command = new DelegatingCommand(OnAddExistingFile, OnCanAddExistingFile)},
                   };
            }
        }
        
        private bool OnCanAddExistingFile()
        {
            var openFiles = new List<OpenBioDataViewModel>();
            return SendMessage(ViewMessages.QueryOpenViewModels, openFiles) && openFiles.Count > 0 &&
                   Categories.SelectMany(cat => cat.Children).Intersect(openFiles).Count() != openFiles.Count;
        }

        private void OnAddExistingFile()
        {
            var openFiles = new List<OpenBioDataViewModel>();
            SendMessage(ViewMessages.QueryOpenViewModels, openFiles);

            if (openFiles.Count > 0)
            {
                AddOpenFileViewModel afvm = new AddOpenFileViewModel(openFiles, Categories.SelectMany(cat => cat.Children));
                IUIVisualizer uiVisualizer = Resolve<IUIVisualizer>();
                if (uiVisualizer != null)
                {
                    bool? result = uiVisualizer.ShowDialog(typeof (AddOpenFileView).ToString(), afvm);
                    if (result != null && result.Value)
                    {
                        foreach (var file in afvm.SelectedFiles)
                        {
                            AddFileToWorkspace(new WorkspaceEntry
                                                   {
                                                       FormatType = file.FormatType,
                                                       LoaderData = file.LoadData,
                                                       LoaderKey = file.LoaderKey
                                                   });
                        }
                    }
                }
            }
        }

        private bool OnCanOpenWorkspace()
        {
            return Categories.Any(cat => cat.Children.Where(child => child.IsLoaded).FirstOrDefault() == null);
        }

        private void OnOpenWorkspace()
        {
            IsOpen = true;
            foreach (var cat in Categories)
                foreach (var child in cat.Children)
                    child.Load();
        }

        private bool OnCanCloseWorkspace()
        {
            return Categories.Any(cat => cat.Children.Where(child => child.IsLoaded).FirstOrDefault() != null);
        }

        private void OnCloseWorkspace()
        {
            IsOpen = false;
            foreach (var cat in Categories)
                foreach (var child in cat.Children)
                    child.CloseCommand.Execute(null);
        }

        private void OnRemoveWorkspace()
        {
            SendMessage(ViewMessages.RemoveWorkspace, this);
        }

        public void Save()
        {
            _workspace.DataSources.Clear();
            foreach (var cat in Categories)
            {
                foreach (var vm in cat.Children)
                {
                    _workspace.DataSources.Add(
                        new WorkspaceEntry
                            {LoaderData = vm.LoadData, LoaderKey = vm.LoaderKey, FormatType = vm.FormatType});
                }
            }

            _workspace.Save();
        }
    }
}
